package com.indi.gulimall.auth.controller;

import com.alibaba.fastjson.TypeReference;
import com.indi.common.constant.AuthConstant;
import com.indi.common.enums.BizCodeEnum;
import com.indi.common.to.LoginTO;
import com.indi.common.to.MemberTO;
import com.indi.common.to.RegisterTO;
import com.indi.common.utils.R;
import com.indi.common.utils.RandomUtils;
import com.indi.gulimall.auth.feign.MemberFeignService;
import com.indi.gulimall.auth.feign.ThirdPartyFeignService;
import com.indi.gulimall.auth.mapstruct.AuthCovertBasic;
import com.indi.gulimall.auth.vo.LoginVO;
import com.indi.gulimall.auth.vo.RegisterVO;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.apache.commons.lang.StringUtils;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Controller;
import org.springframework.validation.BindingResult;
import org.springframework.validation.FieldError;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.servlet.mvc.support.RedirectAttributes;

import javax.annotation.Resource;
import javax.servlet.http.HttpSession;
import javax.validation.Valid;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

@Controller
@Api(tags = "用户认证")
public class AuthController {
    @Resource
    private StringRedisTemplate stringRedisTemplate;

    @Resource
    private MemberFeignService memberFeignService;

    @Resource
    private ThirdPartyFeignService thirdPartyFeignService;

    @GetMapping("/login.html")
    public String loginPage(HttpSession session){
        Object attribute = session.getAttribute(AuthConstant.SESSION_ATTR_NAME);
        // 如果 session 中有数据，则说明用户已登录，直接跳转到首页，否则跳转到登录
        if (attribute == null) {
            return "login";
        }else{
            return "redirect:http://gulimall.com";
        }
    }

    @PostMapping("/web/auth/sms/send-code")
    @ResponseBody
    @ApiOperation("发送验证码")
    public R sendCode(@RequestParam("phoneNum") String phoneNum) {
        // value：验证码_发送验证码的时间戳
        String redisCode = stringRedisTemplate.opsForValue().get(AuthConstant.SMS_CODE_PREFIX + phoneNum);
        if (StringUtils.isNotEmpty(redisCode)) {
            String[] s = redisCode.split("_");
            if (System.currentTimeMillis() - Long.parseLong(s[1]) <= 60000) {
                // 同一手机号在60s内多次尝试获取验证码
                return R.error(BizCodeEnum.SMS_CODE_EXCEPTION);
            }
        }

        String code = RandomUtils.getFourBitRandom();
        stringRedisTemplate.opsForValue().set(AuthConstant.SMS_CODE_PREFIX + phoneNum,
                code + "_" + System.currentTimeMillis(), 10, TimeUnit.MINUTES);
        // 调用阿里云sdk发送短信
//        thirdPartyFeignService.sendCode(phoneNum, code);
        return R.ok();
    }

    /**
     * 重定向携带数据，是利用的session原理。将数据放在session中 ，只要调到下一个页面，取出这个数据以后，session里面的数据就会删掉
     * TODO 但是会出现分布式的session问题
     *
     * @param registerVO
     * @param result
     * @param redirectAttributes
     * @return
     */
    @PostMapping("/web/auth/register")
    @ApiOperation("注册")
    public String register(@Valid RegisterVO registerVO, BindingResult result, RedirectAttributes redirectAttributes) {
        if (result.hasErrors()) {
            jsrErrors(result, redirectAttributes);
            return "redirect:http://auth.gulimall.com/register.html";
        }

        // 校验验证码
        String code = registerVO.getCode();
        String redisCode = stringRedisTemplate.opsForValue().get(AuthConstant.SMS_CODE_PREFIX + registerVO.getPhoneNum());
        Map<String, String> errors = new HashMap<>();

        if (StringUtils.isNotEmpty(redisCode)) {
            String[] s = redisCode.split("_");
            if (code.equals(s[0])) {
                stringRedisTemplate.delete(AuthConstant.SMS_CODE_PREFIX + registerVO.getPhoneNum());
                // 校验通过
                RegisterTO registerTO = AuthCovertBasic.INSTANCE.registerVOToRegisterTO(registerVO);
                R r = memberFeignService.register(registerTO);
                if (r.getCode() == 0) {
                    return "redirect:http://auth.gulimall.com/login.html";
                } else {
                    errors.put("msg", r.getMsg());
                }
            } else {
                errors.put("code", "验证码错误");
            }
        } else {
            errors.put("code", "验证码错误");
        }
        redirectAttributes.addFlashAttribute("errors", errors);
        return "redirect:http://auth.gulimall.com/register.html";
    }

    /**
     * 封装jsr的异常信息
     *
     * @param result
     * @param redirectAttributes
     */
    private void jsrErrors(BindingResult result, RedirectAttributes redirectAttributes) {
        Map<String, String> errors = result.getFieldErrors().stream().collect(Collectors.toMap(FieldError::getField,
                FieldError::getDefaultMessage, (last, next) -> next));
        redirectAttributes.addFlashAttribute("errors", errors);
    }

    @PostMapping("/web/auth/login")
    public String login(@Valid LoginVO loginVO, BindingResult result, RedirectAttributes redirectAttributes,
                        HttpSession session) {
        if (result.hasErrors()) {
            jsrErrors(result, redirectAttributes);
            return "redirect:http://auth.gulimall.com/login.html";
        }
        LoginTO loginTO = AuthCovertBasic.INSTANCE.loginVOToLoginTO(loginVO);
        R r = memberFeignService.login(loginTO);

        if (r.getCode() == 0) {
            MemberTO data = r.getData(new TypeReference<MemberTO>() {
            });
            // 将登录的用户信息放到 session 中
            session.setAttribute(AuthConstant.SESSION_ATTR_NAME, data);
            return "redirect:http://gulimall.com";
        } else {
            Map<String, String> errors = new HashMap<>();
            errors.put("msg", r.getMsg());
            redirectAttributes.addFlashAttribute("errors", errors);
            return "redirect:http://auth.gulimall.com/login.html";
        }
    }
}
